package com.gubei.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.gson.Gson;
import com.gubei.auth.common.enums.AuthUserStatusEnum;
import com.gubei.auth.common.enums.IsDeletedFlagEnum;
import com.gubei.auth.domain.constants.AuthConstant;
import com.gubei.auth.domain.convert.AuthUserBOConverter;
import com.gubei.auth.domain.entity.AuthUserBO;
import com.gubei.auth.domain.redis.RedisUtil;
import com.gubei.auth.domain.service.AuthUserDomainService;
import com.gubei.auth.infra.basic.entity.*;
import com.gubei.auth.infra.basic.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUserDomainService {

    @Resource
    private AuthUserService authUserService;

    @Resource
    private AuthUserRoleService authUserRoleService;

    @Resource
    private AuthPermissionService authPermissionService;

    @Resource
    private AuthRolePermissionService authRolePermissionService;

    @Resource
    private AuthRoleService authRoleService;

    @Resource
    private RedisUtil redisUtil;



    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        AuthUser existAuthUser = new AuthUser();
        existAuthUser.setUserName(authUserBO.getUserName());
        List<AuthUser> existUser = authUserService.queryByCondition(existAuthUser);
        if (existUser.size() > 0) {
            return false;
        }
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBoToEntity(authUserBO);
        if (StringUtils.isNotBlank(authUserBO.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), AuthConstant.SALT));
        }
        if (StringUtils.isBlank(authUser.getAvatar())){
            authUser.setAvatar("http://43.138.23.47:9000/gb-club/user/icon/xiaoxin.png");
        }
        if (StringUtils.isBlank(authUser.getNickName())){
            authUser.setNickName("顾北ファン");
        }
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Boolean result = authUserService.insert(authUser) > 0;

        //基本的な役割をユーザーに付与
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstant.NORMAL_USER);
        AuthRole resultRole = authRoleService.queryByCondition(authRole);
        Long roleId = resultRole.getId();
        Long userId = authUser.getId();
        AuthUserRole userRole = new AuthUserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);
        userRole.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        authUserRoleService.insert(userRole);

        String roleKey = redisUtil.buildKey(AuthConstant.AUTH_ROLE_PREFIX,authUser.getUserName());
        List<AuthRole> roleList = new LinkedList<>();
        roleList.add(authRole);
        redisUtil.set(roleKey,new Gson().toJson(roleList));

        //該当役割のパーミッションをクエリ
        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(roleId);
        List<AuthRolePermission> authRolePermissionList = authRolePermissionService.queryByCondition(authRolePermission);

        List<Long> permissionIdList = authRolePermissionList.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        List<AuthPermission> permissionList = authPermissionService.queryByIdList(permissionIdList);
        String permissionKey = redisUtil.buildKey(AuthConstant.AUTH_PERMISSION_PREFIX,authUser.getUserName());
        redisUtil.set(permissionKey,new Gson().toJson(permissionList));
        return result;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBoToEntity(authUserBO);
        Boolean result = authUserService.update(authUser) > 0;
        return result;
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBoToEntity(authUserBO);
        authUser.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        Boolean result = authUserService.update(authUser) > 0;
        AuthUser deletedAuthUser = new AuthUser();
        deletedAuthUser.setId(authUser.getId());
        authUserService.queryById(authUser.getId());
        String roleKey = redisUtil.buildKey(AuthConstant.AUTH_ROLE_PREFIX,authUser.getUserName());
        String permissionKey = redisUtil.buildKey(AuthConstant.AUTH_PERMISSION_PREFIX,authUser.getUserName());
        redisUtil.delete(roleKey);
        redisUtil.delete(permissionKey);
        return result;
    }

    @Override
    public SaTokenInfo doLogin(String validCode) {
        String loginKey = redisUtil.buildKey(AuthConstant.LOGIN_PREFIX,validCode);
        String openId = redisUtil.get(loginKey);
        if (StringUtils.isBlank(openId)) {
            return null;
        }
        AuthUserBO authUserBO = new AuthUserBO();
        authUserBO.setUserName(openId);
        this.register(authUserBO);
        StpUtil.login(openId);
        SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();
        return saTokenInfo;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setUserName(authUserBO.getUserName());
        List<AuthUser> userList = authUserService.queryByCondition(authUser);
        if (CollectionUtils.isEmpty(userList)){
            return new AuthUserBO();
        }
        AuthUser user = userList.get(0);
        AuthUserBO resultBo = AuthUserBOConverter.INSTANCE.convertEntityToBo(user);
        return resultBo;
    }

    @Override
    public List<AuthUserBO> getUserInfoByIds(List<String> userNameList) {
        List<AuthUser> userList = authUserService.getUserInfoByIdList(userNameList);
        if (CollectionUtils.isEmpty(userList)) {
            return Collections.emptyList();
        }
        List<AuthUserBO> authUserBOList = AuthUserBOConverter.INSTANCE.convertEntityListToBoList(userList);
        return authUserBOList;
    }
}
